home *** CD-ROM | disk | FTP | other *** search
/ QRZ! Ham Radio 5 / QRZ Ham Radio Callsign Database - Volume 5.iso / files / tcpip / amiga / rhinosrc.lha / bmutil.c < prev    next >
Encoding:
C/C++ Source or Header  |  1993-05-01  |  22.8 KB  |  1,047 lines

  1. /*
  2.  *    Simple mail user interface for KA9Q IP/TCP package.
  3.  *    A.D. Barksdale Garbee II, aka Bdale, N3EUA
  4.  *    Copyright 1986 Bdale Garbee, All Rights Reserved.
  5.  *    Permission granted for non-commercial copying and use, provided
  6.  *    this notice is retained.
  7.  *    Copyright 1987 1988 Dave Trulli NN2Z, All Rights Reserved.
  8.  *    Permission granted for non-commercial copying and use, provided
  9.  *    this notice is retained.
  10.  *
  11.  *    Ported to NOS at 900120 by Anders Klemets SM0RGV.
  12.  */
  13. #include <stdio.h>
  14. #include <string.h>
  15. #include <ctype.h>
  16. #include <time.h>
  17. #include "global.h"
  18. #include "ftpserv.h"
  19. #include "smtp.h"
  20. #include "proc.h"
  21. #include "usock.h"
  22. #include "socket.h"
  23. #include "telnet.h"
  24. #include "timer.h"
  25. #include "session.h"
  26. #include "files.h"
  27. #include "hardware.h"
  28.  
  29. #define        SETVBUF
  30. #if    defined(UNIX) || defined(MICROSOFT)
  31. #include    <sys/types.h>
  32. #endif
  33. /*
  34. #if    defined(UNIX) || defined(MICROSOFT) || defined(__TURBOC__)
  35. #include    <sys/stat.h>
  36. #endif
  37. #ifdef AZTEC
  38. #include <stat.h>
  39. #endif
  40. */
  41. #include <fcntl.h>
  42. #include "bm.h"
  43. #include "mailbox.h"
  44.  
  45. #ifdef SETVBUF
  46. #define        MYBUF    1024
  47. #endif
  48.  
  49. extern long ftell();
  50. static char Badmsg[] = "Invalid Message number %d\n";
  51. static char Nomail[] = "No messages\n";
  52. static char Noaccess[] = "Unable to access %s\n";
  53. static int readnotes __ARGS((struct mbx *m,FILE *ifile,int update));
  54. static long isnewmail __ARGS((struct mbx *m));
  55. static int initnotes __ARGS((struct mbx *m));
  56. static int lockit __ARGS((struct mbx *m));
  57. static long fsize __ARGS((char *name));
  58. static void mfclose __ARGS((struct mbx *m));
  59. static int tkeywait __ARGS((char *prompt,int flush));
  60.  
  61. static int
  62. initnotes(m)
  63. struct mbx *m;
  64. {
  65.     FILE    *tmpfile();
  66.     FILE    *ifile;
  67.     register struct    let *cmsg;
  68.     char buf[256];
  69.     int     i, ret;
  70.  
  71.     sprintf(buf,"%s/%s.txt",Mailspool,m->area);
  72.     if ((ifile = fopen(buf,READ_TEXT)) == NULLFILE)
  73.         return 0;
  74.     fseek(ifile,0L,2);     /* go to end of file */
  75.     m->mboxsize = ftell(ifile);
  76.     rewind(ifile);
  77.     if(!stricmp(m->area,m->name)) /* our private mail area */
  78.         m->mysize = m->mboxsize;
  79.     if ((m->mfile = tmpfile()) == NULLFILE) {
  80.         (void) fclose(ifile);
  81.         return -1;
  82.     }
  83. #ifdef    SETVBUF
  84.     if (m->stdinbuf == NULLCHAR)
  85.         m->stdinbuf = mallocw(MYBUF);
  86.     setvbuf(ifile, m->stdinbuf, _IOFBF, MYBUF);
  87.     if (m->stdoutbuf == NULLCHAR)
  88.         m->stdoutbuf = mallocw(MYBUF);
  89.     setvbuf(m->mfile, m->stdoutbuf, _IOFBF, MYBUF);
  90. #endif
  91.     m->nmsgs = 0;
  92.     m->current = 0;
  93.     m->change = 0;
  94.     m->newmsgs = 0;
  95.     m->anyread = 0;
  96.     /* Allocate space for reading messages */
  97.     free((char *)m->mbox);
  98.     m->mbox = (struct let *)callocw(Maxlet+1,sizeof(struct let));
  99.     ret = readnotes(m,ifile,0);
  100.     (void) fclose(ifile);
  101. #ifdef SETVBUF
  102.     free(m->stdinbuf);
  103.     m->stdinbuf = NULLCHAR;
  104. #endif
  105.     if (ret != 0)
  106.         return -1;
  107.     for (cmsg = &m->mbox[1],i = 1; i <= m->nmsgs; i++, cmsg++)  
  108.         if ((cmsg->status & BM_READ) == 0) {
  109.             m->newmsgs++;
  110.             if (m->current == 0)
  111.                 m->current = i;
  112.         }
  113.     /* start at one if no new messages */
  114.     if (m->current == 0)
  115.         m->current++;
  116.  
  117.     return 0;
  118. }
  119.  
  120. /* readnotes assumes that ifile is pointing to the first
  121.  * message that needs to be read.  For initial reads of a
  122.  * notesfile, this will be the beginning of the file.  For
  123.  * rereads when new mail arrives, it will be the first new
  124.  * message.
  125.  */
  126. static int
  127. readnotes(m,ifile,update)
  128. struct mbx *m;
  129. FILE *ifile ;
  130. int update;    /* true if this is not the initial read of the notesfile */
  131. {
  132.     char     tstring[LINELEN];
  133.     long    cpos;
  134.     register struct    let *cmsg;
  135.     register char *line;
  136.  
  137.     cmsg = (struct let *)NULL;
  138.     line = tstring;
  139.     while(fgets(line,LINELEN,ifile) != NULLCHAR) {
  140.         /* scan for begining of a message */
  141.         if(strncmp(line,"From ",5) == 0) {
  142.             pwait(NULL);
  143.             cpos = ftell(m->mfile);
  144.             fputs(line,m->mfile);
  145.             if (m->nmsgs == Maxlet) {
  146.                 printf("Mail box full: > %d messages\n",Maxlet);
  147.                 mfclose(m);
  148.                 return -1;
  149.             }
  150.             m->nmsgs++;
  151.             cmsg = &m->mbox[m->nmsgs];
  152.             cmsg->start = cpos;
  153.             if(!update)
  154.                 cmsg->status = 0;
  155.             cmsg->size = strlen(line);
  156.             while (fgets(line,LINELEN,ifile) != NULLCHAR) {
  157.                 if (*line == '\n') { /* done header part */
  158.                     cmsg->size++;
  159.                     putc(*line, m->mfile);
  160.                     break;
  161.                 }
  162.                 if (htype(line) == STATUS) {
  163.                     if (line[8] == 'R') 
  164.                         cmsg->status |= BM_READ;
  165.                     continue;
  166.                 }
  167.                 cmsg->size += strlen(line);
  168.                 if (fputs(line,m->mfile) == EOF) {
  169.                     printf("tmp file: %s",sys_errlist[errno]);
  170.                     mfclose(m);
  171.                     return -1;
  172.                 }
  173.  
  174.             }
  175.         } else if (cmsg) {
  176.             cmsg->size += strlen(line);
  177.             fputs(line,m->mfile);
  178.         }
  179.     }
  180.     return 0;
  181. }
  182.  
  183. /* list headers of a notesfile a message */
  184. int
  185. dolistnotes(argc,argv,p)
  186. int argc;
  187. char *argv[];
  188. void *p;
  189. {
  190.     struct mbx *m;
  191.     register struct    let *cmsg;
  192.     register char    *cp, *s;
  193.     char    smtp_date[SLINELEN], smtp_from[SLINELEN];
  194.     char    smtp_subject[SLINELEN], tstring[LINELEN], type;
  195.     int    start, stop;
  196.     long    size;
  197.     char    *area;
  198.  
  199.     m = (struct mbx *) p;
  200.     if (m->mfile == NULLFILE) {
  201.         printf(Nomail);
  202.         return 0;
  203.     }
  204.  
  205.     area = strdup(m->area);
  206.     while((cp = strchr(area,'/')) != NULLCHAR)
  207.         *cp = '.';
  208.     printf("Mail area: %s  %d message%s -  %d new\n\n",area,m->nmsgs,
  209.         m->nmsgs == 1 ? " " : "s ", m->newmsgs);
  210.     free(area);
  211.  
  212.     stop = m->nmsgs;
  213.     if(m->stype == 'L') {        /* LL (List Latest) command */
  214.          if(argc > 1)
  215.           start = stop - atoi(argv[1]) + 1;
  216.          else
  217.           start = stop;
  218.     }
  219.     else {
  220.          if(argc > 1)
  221.           start = atoi(argv[1]);
  222.          else
  223.           start = 1;
  224.          if(argc > 2)
  225.           stop = atoi(argv[2]);
  226.     }
  227.     if(stop > m->nmsgs)
  228.         stop = m->nmsgs;
  229.     if(start < 1 || start > stop) {
  230.         printf("Invalid range.\n");
  231.         return 0;
  232.     }
  233.     for (cmsg = &m->mbox[start]; start <= stop; start++, cmsg++) {
  234.         *smtp_date = '\0';
  235.         *smtp_from = '\0';
  236.         *smtp_subject = '\0';
  237.         type = ' ';
  238.         fseek(m->mfile,cmsg->start,0);
  239.         size = cmsg->size;
  240.         while (size > 0 && fgets(tstring,sizeof(tstring),m->mfile)
  241.                != NULLCHAR) {
  242.             if (*tstring == '\n')    /* end of header */
  243.                 break;
  244.             size -= strlen(tstring);
  245.             rip(tstring);
  246.             /* handle continuation later */
  247.             if (*tstring == ' '|| *tstring == '\t')
  248.                 continue;
  249.             switch(htype(tstring)) {
  250.             case FROM:
  251.                 cp = getaddress(tstring,0);
  252.                 sprintf(smtp_from,"%.30s",
  253.                     cp != NULLCHAR ? cp : "");
  254.                 break;
  255.             case SUBJECT:
  256.                 sprintf(smtp_subject,"%.34s",&tstring[9]);
  257.                 break;
  258.             case DATE:
  259.                 if ((cp = strchr(tstring,',')) == NULLCHAR)
  260.                     cp = &tstring[6];
  261.                 else
  262.                     cp++;
  263.                 /* skip spaces */
  264.                 while (*cp == ' ') cp++;
  265.                 if(strlen(cp) < 17)
  266.                     break;     /* not a valid length */
  267.                 s = smtp_date;
  268.                 /* copy day */
  269.                 if (atoi(cp) < 10 && *cp != '0') {
  270.                     *s++ = ' ';
  271.                 } else
  272.                     *s++ = *cp++;
  273.                 *s++ = *cp++;
  274.  
  275.                 *s++ = ' ';
  276.                 *s = '\0';
  277.                 while (*cp == ' ')
  278.                     cp++;
  279.                 strncat(s,cp,3);    /* copy month */
  280.                 cp += 3;
  281.                 while (*cp == ' ')
  282.                     cp++;
  283.                 /* skip year */
  284.                 while (isdigit(*cp))
  285.                     cp++;
  286.                 /* copy time */
  287.                 strncat(s,cp,6); /* space hour : min */
  288.                 break;
  289.             case BBSTYPE:
  290.                 type = tstring[16];
  291.                 break;
  292.             case NOHEADER:
  293.                 break;
  294.             }
  295.         }
  296.         if((type == m->stype && m->stype != ' ') || m->stype == ' '
  297.            || m->stype == 'L')
  298.              printf("%c%c%c%3d %-27.27s %-12.12s %5ld %.25s\n",
  299.                  (start == m->current ? '>' : ' '),
  300.                  (cmsg->status & BM_DELETE ? 'D' : ' '),
  301.                  (cmsg->status & BM_READ ? 'Y' : 'N'),
  302.                  start, smtp_from, smtp_date,
  303.                  cmsg->size, smtp_subject);
  304.     }
  305.     return 0;
  306. }
  307.  
  308. /*  save msg on stream - if noheader set don't output the header */
  309. int
  310. msgtofile(m,msg,tfile,noheader)
  311. struct mbx *m;
  312. int msg;
  313. FILE *tfile;   /* already open for write */
  314. int noheader;
  315. {
  316.     char    tstring[LINELEN];
  317.     long     size;
  318.  
  319.     if (m->mfile == NULLFILE) {
  320.         printf(Nomail);
  321.         return -1;
  322.     }
  323.     fseek(m->mfile,m->mbox[msg].start,0);
  324.     size = m->mbox[msg].size;
  325.  
  326.     if (noheader) {
  327.         /* skip header */
  328.         while (size > 0 && fgets(tstring,sizeof(tstring),m->mfile)
  329.                != NULLCHAR) {
  330.             size -= strlen(tstring);
  331.             if (*tstring == '\n')
  332.                 break;
  333.         }
  334.     }
  335.     while (size > 0 && fgets(tstring,sizeof(tstring),m->mfile)
  336.            != NULLCHAR) {
  337.         size -= strlen(tstring);
  338.         fputs(tstring,tfile);
  339.         if (ferror(tfile)) {
  340.             printf("Error writing mail file\n");
  341.             return -1;
  342.         }
  343.     }
  344.     return 0;
  345. }
  346.  
  347. /*  dodelmsg - delete message in current notesfile */
  348. int
  349. dodelmsg(argc,argv,p)
  350. int argc;
  351. char *argv[];
  352. void *p;
  353. {
  354.     struct mbx *m;
  355.     int msg,i;
  356.     m = (struct mbx *) p;
  357.     if (m->mfile == NULLFILE) {
  358.         printf(Nomail);
  359.         return 0;
  360.     }
  361.     for(i = 1; i < argc; ++i) {
  362.         msg = atoi(argv[i]);
  363.         if(msg < 0 || msg > m->nmsgs) {
  364.             printf(Badmsg,msg);
  365.             continue;
  366.         }
  367.         /* Check if we have permission to delete others mail */
  368.         if(!(m->privs & FTP_WRITE) && stricmp(m->area,m->name)) {
  369.             printf(Noperm);
  370.             return 0;
  371.         }
  372.         m->mbox[msg].status |= BM_DELETE;
  373.         printf("Msg %d Killed.\n", msg);
  374.         m->change = 1;
  375.     }
  376.     return 0;
  377. }
  378. /* close the temp file while coping mail back to the mailbox */
  379. int
  380. closenotes(m)
  381. struct mbx *m;
  382. {
  383.     register struct    let *cmsg;
  384.     register char *line;
  385.     char tstring[LINELEN], buf[256];
  386.     long size;
  387.     int i, nostatus = 0, nodelete;
  388.     FILE    *nfile;
  389.  
  390.     if (m->mfile == NULLFILE)
  391.         return 0;
  392.  
  393.     if(!m->change) {        /* no changes were made */
  394.         mfclose(m);
  395.         m->mboxsize = 0;
  396.         return 0;
  397.     }
  398.     /* If this area is a public message area, then we will not add a
  399.      * Status line to indicate that the message has been read.
  400.      */
  401.     nostatus = isarea(m->area);
  402.  
  403.     /* Don't delete messages from public message areas unless you are
  404.      * a BBS.
  405.      */
  406.     if(nostatus)
  407.         nodelete = !(m->privs & SYSOP_CMD);
  408.     else
  409.         nodelete = 0;
  410.  
  411.     /* See if any messages have been forwarded, otherwise just close
  412.      * the file and return since there is nothing to write back.
  413.      */
  414.     if(nostatus && nodelete) {
  415.         for(i=1; i <= m->nmsgs; ++i)
  416.             if(m->mbox[i].status & BM_FORWARDED)
  417.                 break;
  418.         if(i > m->nmsgs) {
  419.             mfclose(m);
  420.             m->mboxsize = 0;
  421.             return 0;
  422.         }
  423.     }
  424.     line = tstring;
  425.     scanmail(m);
  426.     if(lockit(m))
  427.         return -1;
  428.     sprintf(buf,"%s/%s.txt",Mailspool,m->area);
  429.     if ((nfile = fopen(buf,WRITE_TEXT)) == NULLFILE) {
  430.         printf(Noaccess,buf);
  431.         mfclose(m);
  432.         m->mboxsize = 0;
  433.         rmlock(Mailspool,m->area);
  434.         return -1;
  435.     }
  436.     /* copy tmp file back to notes file */
  437.     for (cmsg = &m->mbox[1],i = 1; i <= m->nmsgs; i++, cmsg++) {
  438.         fseek(m->mfile,cmsg->start,0);
  439.         size = cmsg->size;
  440.         /* It is not possible to delete messages if nodelete is set */
  441.         if ((cmsg->status & BM_DELETE) && !nodelete)
  442.             continue;
  443.         /* copy the header */
  444.         while (size > 0 && fgets(line,LINELEN,m->mfile) != NULLCHAR) {
  445.             size -= strlen(line);
  446.             if (*line == '\n') {
  447.                 if (cmsg->status & BM_FORWARDED)
  448.                     fprintf(nfile,"%s%s\n",Hdrs[XFORWARD],
  449.                         m->name);
  450.                 if ((cmsg->status & BM_READ) != 0 && !nostatus)
  451.                     fprintf(nfile,"%sR\n",Hdrs[STATUS]);
  452.                 fprintf(nfile,"\n");
  453.                 break;
  454.             }
  455.             fputs(line,nfile);
  456.             /* pwait(NULL);  can cause problems if exiting NOS */
  457.         }
  458.         while (size > 0 && fgets(line,LINELEN,m->mfile) != NULLCHAR) {
  459.             fputs(line,nfile);
  460.             size -= strlen(line);
  461.             /* pwait(NULL);   dont want no damaged files */
  462.             if (ferror(nfile)) {
  463.                 printf("Error writing mail file\n");
  464.                 (void) fclose(nfile);
  465.                 mfclose(m);
  466.                 m->mboxsize = 0;
  467.                 rmlock(Mailspool,m->area);
  468.                 return -1;
  469.             }
  470.         }
  471.     }
  472.     m->nmsgs = 0;
  473.     if (!stricmp(m->name,m->area))
  474.         m->mysize = ftell(nfile); /* Update the size of our mailbox */
  475.     /* remove a zero length file */
  476.     if (ftell(nfile) == 0L)
  477.         (void) unlink(buf);
  478.     (void) fclose(nfile);
  479.     mfclose(m);
  480.     m->mboxsize = 0;
  481.     rmlock(Mailspool,m->area);
  482.     pwait(NULL);
  483.     return 0;
  484. }
  485.  
  486. /* Returns 1 if name is a public message Area, 0 otherwise */
  487. int
  488. isarea(name)
  489. char *name;
  490. {
  491.     char buf[LINELEN], *cp;
  492.     FILE *fp;
  493.     if((fp = fopen(Arealist,READ_TEXT)) == NULLFILE)
  494.         return 0;
  495.     while(fgets(buf,sizeof(buf),fp) != NULLCHAR) {
  496.         /* The first word on each line is all that matters */
  497.         if((cp = strchr(buf,' ')) == NULLCHAR)
  498.             if((cp = strchr(buf,'\t')) == NULLCHAR)
  499.                 continue;
  500.         *cp = '\0';
  501.         if((cp = strchr(buf,'\t')) != NULLCHAR)
  502.             *cp = '\0';
  503.         if(stricmp(name,buf) == 0) {    /* found it */
  504.             fclose(fp);
  505.             return 1;
  506.         }
  507.     }
  508.     fclose(fp);
  509.     return 0;
  510. }
  511.  
  512. static int
  513. lockit(m)
  514. struct mbx *m;
  515. {
  516.     int c, cnt = 0;
  517.  
  518.     while(mlock(Mailspool,m->area)) {
  519.         pause(1000L/MSPTICK);    /* Wait one second */
  520.         if(++cnt == 10) {
  521.             cnt = 0;
  522.             c = tkeywait("Mail file is busy, Abort or Retry ? ",1);
  523.             if (c == 'A' || c == 'a' || c == EOF) {
  524.                 mfclose(m);
  525.                 return 1;
  526.             }
  527.         }
  528.     }
  529.     return 0;
  530. }
  531.  
  532. /* read the next message or the current one if new */
  533. int
  534. doreadnext(argc,argv,p)
  535. int argc;
  536. char *argv[];
  537. void *p;
  538. {
  539.     struct mbx *m;
  540.     char buf[10], *newargv[2];
  541.     m = (struct mbx *) p;
  542.     if (m->mfile == NULLFILE)
  543.         return 0;
  544.     if ((m->mbox[m->current].status & BM_READ) != 0) {
  545.         if (m->current == 1 && m->anyread == 0)
  546.             ;
  547.         else if (m->current < m->nmsgs) {
  548.             m->current++;
  549.         } else {
  550.             printf("Last message\n");
  551.             return 0;
  552.         }
  553.     }
  554.     sprintf(buf,"%d",m->current);
  555.     newargv[0] = "read";
  556.     newargv[1] = buf;
  557.     m->anyread = 1;
  558.     return doreadmsg(2,newargv,p);
  559. }
  560.  
  561. /*  display message on the crt given msg number */
  562. int
  563. doreadmsg(argc,argv,p)
  564. int argc;
  565. char *argv[];
  566. void *p;
  567. {
  568.     struct mbx *m;
  569.     register int c, col, lin;
  570.     char    buf[MAXCOL+2], *cp, *cp2;
  571.     int    msg, cnt, i, usemore, verbose, mbxheader, pathcol;
  572.     int    header, lastheader;
  573.     long     size;
  574.  
  575.     m = (struct mbx *) p;
  576.     if (m->mfile == NULLFILE) {
  577.         printf(Nomail);
  578.         return 0;
  579.     }
  580.     if(m->type == TELNET || m->type == TIP)
  581.         usemore = 1;    /* Display More prompt */
  582.     else
  583.         usemore = 0;
  584.     lin = MAXLIN-1;
  585.     for(i = 1; i < argc; ++i) {
  586.         msg = atoi(argv[i]);
  587.         if( msg < 1 || msg > m->nmsgs) {
  588.             printf(Badmsg,msg);
  589.             return 0;
  590.         }
  591.         fseek(m->mfile,m->mbox[msg].start,0);
  592.         size = m->mbox[msg].size;
  593.         m->current = msg;
  594.         header = NOHEADER;
  595.         mbxheader = 0;
  596.         if(*argv[0] == 'v')
  597.             verbose = 1;    /* display all header lines */
  598.         else
  599.             verbose = 0;
  600.  
  601.         printf("Message #%d %s\n", msg,
  602.             m->mbox[msg].status & BM_DELETE ? "[Deleted]" : "");
  603.         if ((m->mbox[msg].status & BM_READ) == 0) {
  604.             m->mbox[msg].status |= BM_READ;
  605.             m->change = 1;
  606.             m->newmsgs--;
  607.         }
  608.         --lin;
  609.         col = 0;
  610.         while (!feof(m->mfile) && size > 0) {
  611.             for (col = 0;  col < MAXCOL;) {
  612.                 c = getc(m->mfile);
  613.                 size--;
  614.                 if (feof(m->mfile) || size == 0) /* end this line */
  615.                     break;
  616.                 if (c == '\t') {
  617.                     cnt = col + 8 - (col & 7);
  618.                     if (cnt >= MAXCOL) /* end this line */
  619.                         break;
  620.                     while (col < cnt)
  621.                         buf[col++] = ' ';
  622.                 } else {
  623.                     if (c == '\n')
  624.                         break;
  625.                     buf[col++] = c;
  626.                 }
  627.             }
  628.             if(col < MAXCOL)
  629.                 buf[col++] = '\n';
  630.             buf[col] = '\0';
  631.             if(mbxheader > 0) {
  632.                  /* Digest R: lines and display as a Path: line */
  633.                  if(strncmp(buf,"R:",2) != 0 ||
  634.                 (cp = strchr(buf,'@')) == NULLCHAR) {
  635.                   putchar('\n');
  636.                   mbxheader = -1; /* don't get here again */
  637.                   verbose = 1;
  638.                  }
  639.                  else {
  640.                   if(*(++cp) == ':')
  641.                        ++cp;
  642.                   for(cp2 = cp; isalnum(*cp2); ++cp2)  ;
  643.                   *cp2 = '\0';
  644.                   if(mbxheader++ == 1) {
  645.                        puts("Path: ");
  646.                        pathcol = 5;
  647.                        --lin;
  648.                   }
  649.                   else {
  650.                        putchar('!');
  651.                        if(++pathcol + strlen(cp) > MAXCOL-3){
  652.                         puts("\n      ");
  653.                         pathcol = 5;
  654.                         --lin;
  655.                        }
  656.                   }
  657.                   puts(cp);
  658.                   pathcol += strlen(cp);
  659.                   ++lin;    /* to allow for not printing it later */
  660.                  }
  661.             }
  662.             if(col == 1 && !verbose && !mbxheader)
  663.                  /* last header line reached */
  664.                  mbxheader = 1;
  665.             if(verbose)
  666.                 puts(buf);
  667.             if(!verbose && !mbxheader){
  668.                 lastheader = header;
  669.                 if(!isspace(*buf))
  670.                     header = htype(buf);
  671.                 else
  672.                     header = lastheader;
  673.                 switch(header) {
  674.                 case TO:
  675.                 case CC:
  676.                 case FROM:
  677.                 case DATE:
  678.                 case SUBJECT:
  679.                 case APPARTO:
  680.                 case ORGANIZATION:
  681.                     puts(buf);
  682.                     break;
  683.                 default:
  684.                     ++lin;
  685.                 }
  686.             }
  687.             col = 0;
  688.             if(usemore && --lin == 0){
  689.                 c = tkeywait("--More--",0);
  690.                 lin = MAXLIN-1;
  691.                 if(c == -1 || c == 'q' || c == 'Q')
  692.                     break;
  693.                 if(c == '\n' || c == '\r')
  694.                     lin = 1;
  695.             }
  696.         }
  697.     }
  698.     return 0;
  699. }
  700.  
  701. /* Set up m->to when replying to a message. The subject is returned in
  702.  * m->line.
  703.  */
  704. int
  705. mbx_reply(argc,argv,m,cclist,rhdr)
  706. int argc;
  707. char *argv[];
  708. struct mbx *m;
  709. struct list **cclist;    /* Pointer to buffer for pointers to cc recipients */
  710. char **rhdr;        /* Pointer to buffer for extra reply headers */
  711. {
  712.     char subject[MBXLINE], *msgid = NULLCHAR, *date = NULLCHAR;
  713.     char *cp;
  714.     int msg, lastheader, header = NOHEADER;
  715.     long size;
  716.  
  717.     /* Free anything that might be allocated
  718.      * since the last call to mbx_to() or mbx_reply()
  719.      */
  720.     free(m->to);
  721.     m->to = NULLCHAR;
  722.     free(m->tofrom);
  723.     m->tofrom = NULLCHAR;
  724.     free(m->tomsgid);
  725.     m->tomsgid = NULLCHAR;
  726.     free(m->origto);
  727.     m->origto = NULLCHAR;
  728.     subject[0] = '\0';
  729.  
  730.     if(argc == 1)
  731.          msg = m->current;
  732.     else
  733.          msg = atoi(argv[1]);
  734.     if (m->mfile == NULLFILE) {
  735.          if(m->sid & MBX_SID)
  736.           puts("NO - ");
  737.         puts(Nomail);
  738.         return 0;
  739.     }
  740.     if(msg < 1 || msg > m->nmsgs) {
  741.          if(m->sid & MBX_SID)
  742.           puts("NO - ");
  743.          puts(Badmsg);
  744.          return -1;
  745.     }
  746.     fseek(m->mfile,m->mbox[msg].start,0);
  747.     size = m->mbox[msg].size;
  748.     m->current = msg;
  749.     while(size > 0 && fgets(m->line,MBXLINE-1,m->mfile) != NULLCHAR) {
  750.          size -= strlen(m->line);
  751.          if(m->line[0] == '\n')    /* end of header */
  752.           break;
  753.          rip(m->line);
  754.          lastheader = header;
  755.          if(!isspace(m->line[0])) {
  756.           header = htype(m->line);
  757.           lastheader = NOHEADER;
  758.          }
  759.          switch(header) {
  760.          case SUBJECT:
  761.           if(strlen(m->line) > 11 && !strnicmp(&m->line[9],"Re:",3))
  762.                strcpy(subject,&m->line[9]);
  763.           else
  764.                sprintf(subject,"Re: %s",&m->line[9]);
  765.           break;
  766.          case FROM:
  767.           if(m->to == NULLCHAR && (cp = getaddress(m->line,0)) !=
  768.              NULLCHAR)
  769.                m->to = strdup(cp);
  770.           break;
  771.          case REPLYTO:
  772.           if((cp = getaddress(m->line,0)) != NULLCHAR) {
  773.                free(m->to);
  774.                m->to = strdup(cp);
  775.           }
  776.           break;
  777.          case MSGID:
  778.           free(msgid);
  779.           msgid = strdup(&m->line[12]);
  780.           break;
  781.          case DATE:
  782.           free(date);
  783.           date = strdup(&m->line[6]);
  784.           break;
  785.          case TO:
  786.          case CC:
  787.          case APPARTO:
  788.           /* Get addresses on To, Cc and Apparently-To lines */
  789.           cp = m->line;
  790.           m->line[strlen(cp)+1] = '\0';    /* add extra null at end */
  791.           for(;;) {
  792.                if((cp = getaddress(cp,lastheader == header ||
  793.                        cp != m->line)) == NULLCHAR)
  794.                 break;
  795.                addlist(cclist,cp,0);
  796.                /* skip to next address, if any */
  797.                cp += strlen(cp) + 1;
  798.           }
  799.           break;
  800.          }
  801.     }
  802.     if(msgid != NULLCHAR || date != NULLCHAR) {
  803.          *rhdr = mallocw(LINELEN);
  804.          sprintf(*rhdr,"In-Reply-To: your message ");
  805.          if(date != NULLCHAR) {
  806.           sprintf(m->line,"of %s.\n",date);
  807.           strcat(*rhdr,m->line);
  808.           if(msgid != NULLCHAR)
  809.                strcat(*rhdr,"             ");
  810.          }
  811.          if(msgid != NULLCHAR) {
  812.           sprintf(m->line,"%s\n",msgid);
  813.           strcat(*rhdr,m->line);
  814.          }
  815.          free(msgid);
  816.          free(date);
  817.     }
  818.     strcpy(m->line,subject);
  819.     return 0;
  820. }
  821.  
  822. void
  823. scanmail(m)         /* Get any new mail */
  824. struct mbx *m;
  825. {
  826.     FILE *nfile;
  827.     int ret, cnt;
  828.     char buf[256];
  829.     long diff;
  830.  
  831.     if ((diff = isnewmail(m)) == 0L)
  832.         return;
  833.     if(lockit(m))
  834.         return;
  835.     if(m->mfile == NULLFILE || diff < 0L) {
  836.         /* This is the first time scanmail is called, or the
  837.          * mail file size has decreased. In the latter case,
  838.          * any changes we did to this area will be lost, but this
  839.          * is not fatal.
  840.          */
  841.         initnotes(m);
  842.         rmlock(Mailspool,m->area);
  843.         return;
  844.     }
  845.     sprintf(buf,"%s/%s.txt",Mailspool,m->area);
  846.     if ((nfile = fopen(buf,READ_TEXT)) == NULLFILE)
  847.         printf(Noaccess,buf);
  848.     else {
  849.         /* rewind tempfile */
  850.         fseek(m->mfile,0L,0);
  851.         cnt = m->nmsgs;
  852.         /* Reread all messages since size they may have changed
  853.          * in size after a X-Forwarded-To line was added.
  854.          */
  855.         m->nmsgs = 0;
  856.         ret = readnotes(m,nfile,1);   /* get the mail */
  857.         m->newmsgs += m->nmsgs - cnt;
  858.         m->mboxsize = ftell(nfile);
  859.         if(!stricmp(m->name,m->area))
  860.             m->mysize = m->mboxsize;
  861.         (void) fclose(nfile);
  862.         if (ret != 0)
  863.             printf("Error updating mail file\n");
  864.     }
  865.     rmlock(Mailspool,m->area);
  866. }
  867.  
  868. /* Check the current mailbox to see if new mail has arrived.
  869.  * Returns the difference in size.
  870.  */
  871. static long
  872. isnewmail(m)
  873. struct mbx *m;
  874. {
  875.     char buf[256];
  876.     sprintf(buf,"%s/%s.txt",Mailspool,m->area);
  877.     return fsize(buf) - m->mboxsize;
  878. }
  879.  
  880. /* Check if the private mail area has changed */
  881. long
  882. isnewprivmail(m)
  883. struct mbx *m;
  884. {
  885.     long cnt;
  886.     char buf[256];
  887.     sprintf(buf,"%s/%s.txt",Mailspool,m->name);
  888.     cnt = m->mysize;
  889.     m->mysize = fsize(buf);
  890.     return m->mysize - cnt; /* != 0 not more than once */
  891. }
  892.  
  893. char *Hdrs[] = {
  894.     "Approved: ",
  895.     "From: ",
  896.     "To: ",
  897.     "Date: ",
  898.     "Message-Id: ",
  899.     "Subject: ",
  900.     "Received: ",
  901.     "Sender: ",
  902.     "Reply-To: ",
  903.     "Status: ",
  904.     "X-BBS-Msg-Type: ",
  905.     "X-Forwarded-To: ",
  906.     "Cc: ",
  907.     "Return-Receipt-To: ",
  908.     "Apparently-To: ",
  909.     "Errors-To: ",
  910.     "Organization: ",
  911.     NULLCHAR
  912. };
  913.  
  914. /* return the header type */
  915. int
  916. htype(s)
  917. char *s;
  918. {
  919.     register char *p;
  920.     register int i;
  921.  
  922.     p = s;
  923.     /* check to see if there is a ':' before and white space */
  924.     while (*p != '\0' && *p != ' ' && *p != ':')
  925.         p++;
  926.     if (*p != ':')
  927.         return NOHEADER;
  928.  
  929.     for (i = 0; Hdrs[i] != NULLCHAR; i++) {
  930.         if (strnicmp(Hdrs[i],s,strlen(Hdrs[i])) == 0)
  931.             return i;
  932.     }
  933.     return UNKNOWN;
  934. }
  935.  
  936. /* This function returns the length of a file. The proper thing would be
  937.  * to use stat(), but it fails when using DesqView together with Turbo-C
  938.  * code.
  939.  */
  940. static long
  941. fsize(name)
  942. char *name;
  943. {
  944.     long cnt;
  945.     FILE *fp;
  946.     if((fp = fopen(name,READ_TEXT)) == NULLFILE)
  947.         return -1L;
  948.     fseek(fp,0L,2);
  949.     cnt = ftell(fp);
  950.     fclose(fp);
  951.     return cnt;
  952. }
  953.  
  954. /* close the temporary mail file */
  955. static void
  956. mfclose(m)
  957. struct mbx *m;
  958. {
  959.     if(m->mfile != NULLFILE)
  960.         fclose(m->mfile);
  961.     m->mfile = NULLFILE;
  962. #ifdef SETVBUF
  963.     free(m->stdoutbuf);
  964.     m->stdoutbuf = NULLCHAR;
  965. #endif
  966. }
  967.  
  968. /* Parse a string in the "Text: <user@host>" or "Text: user@host (Text)"
  969.  * format for the address user@host.
  970.  */
  971. char *
  972. getaddress(string,cont)
  973. char *string;
  974. int cont;        /* true if string is a continued header line */
  975. {
  976.     char *cp, *ap = NULLCHAR;
  977.     int par = 0;
  978.     if((cp = getname(string)) != NULLCHAR) /* Look for <> style address */
  979.          return cp;
  980.     cp = string;
  981.     if(!cont)
  982.          if((cp = strchr(string,':')) == NULLCHAR)    /* Skip the token */
  983.           return NULLCHAR;
  984.          else
  985.           ++cp;
  986.     for(; *cp != '\0'; ++cp) {
  987.          if(par && *cp == ')') {
  988.           --par;
  989.           continue;
  990.          }
  991.          if(*cp == '(')        /* Ignore text within parenthesis */
  992.           ++par;
  993.          if(par)
  994.           continue;
  995.          if(*cp == ' ' || *cp == '\t' || *cp == '\n' || *cp == ',') {
  996.           if(ap != NULLCHAR)
  997.                break;
  998.           continue;
  999.          }
  1000.          if(ap == NULLCHAR)
  1001.           ap = cp;
  1002.     }
  1003.     *cp = '\0';
  1004.     return ap;
  1005. }
  1006.  
  1007. /* Print prompt and read one character, telnet version */
  1008. static int
  1009. tkeywait(prompt,flush)
  1010. char *prompt;    /* Optional prompt */
  1011. int flush;    /* Flush queued input? */
  1012. {
  1013.     int c, i, oldimode,oldomode;
  1014.  
  1015.     if(flush && socklen(fileno(stdin),0) != 0)
  1016.         recv_mbuf(fileno(stdin),NULL,0,NULLCHAR,0); /* flush */
  1017.     if(prompt == NULLCHAR)
  1018.         prompt = "Hit enter to continue"; 
  1019.     printf("%s%c%c%c",prompt,IAC,WILL,TN_ECHO);
  1020.     fflush(stdout);
  1021.  
  1022.     /* discard the response */
  1023.  
  1024.     oldimode = fmode(stdin,STREAM_BINARY);
  1025.     oldomode = fmode(stdout,STREAM_BINARY);
  1026.  
  1027.     while((c = getchar()) == IAC){
  1028.         c = getchar();
  1029.         if(c > 250 && c < 255)
  1030.             getchar();
  1031.     }
  1032.  
  1033.     fmode(stdout,oldomode);
  1034.     fmode(stdin,oldimode);
  1035.  
  1036.     /* Get rid of the prompt */
  1037.     for(i=strlen(prompt);i != 0;i--)
  1038.         putchar('\b');
  1039.     for(i=strlen(prompt);i != 0;i--)
  1040.         putchar(' ');
  1041.     for(i=strlen(prompt);i != 0;i--)
  1042.         putchar('\b');
  1043.     printf("%c%c%c",IAC,WONT,TN_ECHO);
  1044.     fflush(stdout);
  1045.     return c;
  1046. }
  1047.